const { chromium } = require('playwright');
const fs = require('fs');
const crypto = require('crypto');
const execSync = require('child_process').execSync;
const PGutils = require("./pgUtils")
const HtmlInfo = require("./htmlInfo");
const ClickInfo = require("./clickInfo");
const pgUtils = require('./pgUtils');
const md5_url = {};

const cssBody = `
<link ref="./css/common.css"></link>
<script type="text/javascript" src="/crypto-js.min.js"></script>
<script type="text/javascript" src="/jquery.js"></script>
<script type="text/javascript" src="/loadpage.js"></script>
<script type="text/javascript" src="/setIframe.js"></script>
`;

const filePath = "C:\\Users\\topnet\\Desktop\\新建文件夹\\";

const url = 'http://192.168.3.110:10002/aaf/';
const systemName = 'saas';



(async () => {
    const browser = await chromium.launch({ channel: 'chrome', headless: false });
    const context = await browser.newContext({ viewport: null });
    const page = await context.newPage();
    await page.goto(url, { waitUntil: 'load' });

    // 监听导航事件
    page.on('framenavigated', async () => handleNavigationInterception(page, context));
    page.on('popup', async popup => handleNewPage(popup, context));
    page.on('load', async () => saveMhtml(page, context, '1'));

    await saveMhtml(page, context, '1');

    // 暴露一个函数到页面上下文
    await page.exposeFunction('handleClick', handleClick);

    // 在页面中注入脚本来监听点击事件
    await pageEvaluateClick(page);

    await page.waitForTimeout(5000000);


    async function handleNavigationInterception(page, context) {
        await pageEvaluateClick(page);

        console.log(`导航页面 >> ${page.url()}`);
        console.log(`导航页面的iframe >> ${page.frames().length}`);

        
        //监听iframe的变化
        await page.on('frameattached', frameattachedHandler)
        await page.on('framenavigated', framenavigatedHandler)


        const frames = await page.frames();
        const urlMd5Vlaue = crypto.createHash('md5').update(page.url()).digest('hex');
        for (let i = 0; i < frames.length; i++) {
            let iframe = frames[i]
            if (iframe.url() == page.url()) {
                continue;
            }

            if (iframe.url() == "about:blank") {
                continue;
            }


            if (!iframe.url()) {
                continue;
            }
            const IframePage = await context.newPage();
            try {

                await IframePage.goto(iframe.url());
                context.pages()[0].bringToFront()
                await IframePage.waitForTimeout(2000);
                await saveMhtml(IframePage, context, '2', urlMd5Vlaue)

            } catch (error) {
                console.error(`iframe load error >>> : ${error.message}`);
            } finally {
                IframePage.close();
            }

            page.on("response", (response) => {

                const url = new URL(response.url());
    
    
    
                if (!(response.url().indexOf(".png")>0 || 
                    response.url().indexOf(".woff2") > 0|| 
                        response.url().indexOf(".js") > 0 || 
                        response.url().indexOf(".woff") > 0|| 
                            response.url().indexOf(".css") > 0)) {
                    let clickInfoMd5 = url.searchParams.get('clickInfoMd5Value')
                    let preUrlMd5 = url.searchParams.get('preUrlMd5')
    
    
    
                    if (clickInfoMd5 == null || !clickInfoMd5) {
                        return;
                    }
    
                    console.log(`Iframeage点击事件 >>> url :  ${response.url()}`);
                    const reponseUrlMd5 = crypto.createHash('md5').update(response.url()).digest('hex')
                    pgUtils.query(`select is_frame from html_info where url_md5 = '${reponseUrlMd5}'`).then(result => {
                        if(result){
    
                            
                            console.log(`Iframeage点击事件 >>>clickInfoMd5 :  ${clickInfoMd5}  preUrl is_iframe ${result.is_frame}  preUrlMd5 = ${preUrlMd5}`);
                            let values = [reponseUrlMd5, result.is_frame, clickInfoMd5, preUrlMd5]
                            
                            pgUtils.insert("update click_info set target_url_md5 = $1,is_frame=$2 where click_info_md5 = $3 and current_url_md5=$4", values)
                            
                        }
    
    
                    })
    
                }
    
    
            })
                    



        }

        
        await saveMhtml(page, context, '1');

    }

    async function frameattachedHandler(iframe){

  
        console.log(`Frame attached: ${iframe.url()}`)
    }


    async function framenavigatedHandler(iframe){
        console.log(`framenavigatedHandler ${iframe.url()}`)
    }
    async function handleNewPage(newPage, context) {

        const activePage = context.pages().slice(-1)[0];

        await pageEvaluateClick(activePage);


        await saveMhtml(activePage, context, '1');
        await activePage.exposeFunction('handleClick', handleClick);
        console.log(`New page opened: ${newPage.url()}`);
    }


    async function saveMhtml(page, context, isFrame, parentUrlMd5) {

        try {
            await page.waitForLoadState('domcontentloaded');
            await page.waitForLoadState('networkidle');
            await page.waitForTimeout(3000);
        } catch (error) {
            console.error(`waitForLoadState: ${error.message}`);
        }


        if (!page) {
            console.log(`page is none >> ${page.url()}`);
            return;
        }

        const urlMd5Vlaue = crypto.createHash('md5').update(page.url()).digest('hex');

        //页面已经存在不需要重复保存
        const queryResult = await pgUtils.query(`select count(*) from html_info where url_md5 = '${urlMd5Vlaue}'`)
        if (queryResult.count > 0) {
            console.log(`页面已经存在，重复保存 >> ${urlMd5Vlaue}`);
            return;
        }


        const filename = `${filePath}${urlMd5Vlaue}.mhtml`;
        const filenameHtml = `${filePath}${urlMd5Vlaue}.html`;

        md5_url[urlMd5Vlaue] = page.url();
        var json_url = JSON.stringify(md5_url, "", "\t");



        console.log(` md5-url >>> ${json_url}`)
        try {
            const client = await context.newCDPSession(page);
            const { data: mhtml_content } = await client.send('Page.captureSnapshot', { format: 'mhtml' });

            // const cleanedContent = removeMultipleEmptyLines(mhtml_content);
            const htmlTitle = await page.title();
            console.log(`[filename >>>: ${filename}], 网站标题：${htmlTitle}`);
            fs.writeFileSync(filename, mhtml_content, 'utf-8');

            const output = execSync(`mhtml2html ${filename} ${filenameHtml}`).toString();


            fs.appendFileSync(filenameHtml, cssBody, 'utf-8');

            console.log(`[转换完成 >>>: ${filenameHtml}]`);

            let html_info = new HtmlInfo(isFrame, htmlTitle, page.url(), filenameHtml, systemName, urlMd5Vlaue, parentUrlMd5)

            pgUtils.insert(html_info.getInsertSql(), html_info.getInsertValues())
            // const htmlContent = fs.readFileSync(filenameHtml, 'utf-8');
            // const $ = cheerio.load(htmlContent);

            // $('iframe').each((index, element) => {
            //     const iframeSrc = $(element).attr('src');
            //     if (iframeSrc) {
            //         const resourcePath = path.join(resourceDir, path.basename(iframeSrc));
            //         $(element).attr('src', resourcePath);
            //     }
            // });

            // fs.writeFileSync(htmlFile, $.html(), 'utf-8');

        } catch (error) {
            console.error(`Failed to generate MHTML: ${error.message}`);
        }
    }


    async function pageEvaluateClick(page) {
        // 在页面中注入脚本来监听点击事件
        try {
            // 在页面中注入脚本来监听点击事件
            await page.evaluate(() => {
                document.addEventListener('click', event => {
                    console.log(window.location.href)
                    let iframes = document.getElementsByTagName("iframe");
                    let index = iframes.length> 0 ? iframes.length -1 : 0
                    console.log(iframes[index].src)
                    window.handleClick({
                        tagName: event.target.tagName,
                        id: event.target.id,
                        target: event.target,
                        className: event.target.className,
                        innerHTML: event.target.innerHTML,
                        text: event.target.textContent,
                        outerHTML: event.target.outerHTML,
                        currentUrl: window.location.href,
                        iframeSrc: iframes[index].src,
                        timestamp: new Date().toISOString()
                    });
                });
            });
        } catch (error) {
            console.error(`addEventListener >>> : ${error.message}`);
        }
    }

    async function handleClick(event) {
        console.log(`Clicked on currentUrl >>>:  current_url = ${event.currentUrl}, text = ${event.text}`);
        let text = event.text.replace("\n", "").replace(/\s+/g, "");
        console.log(`Clicked target new html >>>: ${text}`);


        const urlMd5Vlaue = crypto.createHash('md5').update(event.currentUrl).digest('hex');
        const clickInfoMd5Value = crypto.createHash('md5').update(text).digest('hex');



        //页面已经存在不需要重复保存
        const queryResult = await pgUtils.query(`select count(*) from click_info where current_url_md5='${urlMd5Vlaue}' and click_info_md5 = '${clickInfoMd5Value}'`)
        if (queryResult.count > 0) {
          
            console.log(`点击信息重复保存 ${clickInfoMd5Value} >> ${event.tagName}`);
            return;
        }

        let is_frame = 1;
        let iframeSrcMd5 = '';
        if(event.iframeSrc){
            is_frame = 2;
            iframeSrcMd5 = crypto.createHash('md5').update(event.iframeSrc).digest('hex');
        }
       
        let clickData = new ClickInfo(clickInfoMd5Value,  iframeSrcMd5, urlMd5Vlaue, text,is_frame);
        pgUtils.insert(clickData.getInsertSql(), clickData.getInsertValues())




        // // 设置路由拦截
        await page.route('**/*', route => {

            // 示例：修改或添加 URL 参数
            const url = new URL(route.request().url());
            if (route.request().url().indexOf(".png") > 0||
                route.request().url().indexOf(".svg") > 0 ||
                route.request().url().indexOf(".woff2")> 0 ||
                route.request().url().indexOf(".woff")> 0 ||
                route.request().url().indexOf(".js")> 0 ||
                route.request().url().indexOf(".css")> 0) {
                route.continue({ url: url.toString() });
            } else {
                try {
                    // 例子：修改请求头
                    const x_requested_with = route.request().headers()['x-requested-with'];
                    console.log('拦截请求-x_requested_with:', x_requested_with);
                  
                        url.searchParams.set('clickInfoMd5Value', "clickInfoMd5Value");
                        url.searchParams.set('preUrlMd5', new Date());

                        // 例子：修改请求头

                        console.log('拦截请求:', url.toString());
                        // 继续请求并传入修改后的 URL
                        route.continue({ url: url.toString() });
                    

                } catch (error) {
                    console.log("request error",error)
                }

            }


        });



    }


})();
